package com.cloudlead.common.persistence.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import com.cloudlead.common.lang.exception.RequestNotAcceptableException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

import com.cloudlead.common.lang.SimpleModule;
import com.cloudlead.common.lang.BusinessModule;
import com.cloudlead.common.lang.persistence.IdEntity;
import com.cloudlead.common.persistence.InterpolatedMessage;
import com.cloudlead.common.persistence.Repository;

/**
 * 完成仓储初始化操作的抽象类
 * 
 * @author dean.lu
 * 
 * @param <Pojo>
 *            实体类
 * @param <ID>
 *            主键类
 */
@Transactional(readOnly = true)
public abstract class AbstractInitialRepository<Pojo extends IdEntity<ID>, ID extends Serializable>
		extends SimpleModule implements Repository<Pojo, ID> {

	protected static String ID = "id";

	protected Class<Pojo> entityClass;
	protected Class<ID> primaryKeyClass;

	protected Validator validator;

	public AbstractInitialRepository(BusinessModule module) {
		super(module);
		initType(this.getClass());

		if (hasValidator()) {
			ValidatorFactory validatorFactory = Validation
					.buildDefaultValidatorFactory();
			validator = validatorFactory.getValidator();
		}
	}

	@SuppressWarnings("unchecked")
	private void initType(Class<?> cls) {
		Type superType = cls.getGenericSuperclass();
		if (superType instanceof ParameterizedType) {
			ParameterizedType ptype = (ParameterizedType) superType;
			Type cmpType = ptype.getActualTypeArguments()[0];
			this.entityClass = (Class<Pojo>) cmpType;
			Type cmpType1 = ptype.getActualTypeArguments()[1];
			this.primaryKeyClass = (Class<ID>) cmpType1;
		}
	}

	/**
	 * 是否需要对Pojo进行验证
	 * 
	 * @return
	 */
	protected boolean hasValidator() {
		return true;
	}

	protected void validator(Pojo entity, Class<?>... groups) {
		Set<ConstraintViolation<Pojo>> validatedSet = validator.validate(
				entity, groups);
		if (null != validatedSet && validatedSet.size() > 0) {
			List<InterpolatedMessage> messages = new ArrayList<>();
			for (ConstraintViolation<Pojo> constraintViolation : validatedSet) {
				InterpolatedMessage message = new InterpolatedMessage();
				message.setMessage(constraintViolation.getMessage());
				message.setPropertyPath(constraintViolation.getPropertyPath()
						.toString());
				message.setMessageTemplate(constraintViolation
						.getMessageTemplate());
				message.setRootBeanClass(constraintViolation.getRootBeanClass()
						.getName());
				messages.add(message);
			}
			throw new RequestNotAcceptableException("["
					+ StringUtils.join(messages
							.toArray(new InterpolatedMessage[messages.size()]),
							",") + "]");
		}
	}

}
